package com.android.sreader.format;

import java.io.*;
import java.util.*;
import java.util.zip.*;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.*;
import org.xml.sax.*;

import com.android.sreader.SReaderApplication;
import com.android.sreader.utility.Paragraph;
import com.android.sreader.utility.Paragraph.ParagraphType;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;

public class EpubFile implements Runnable{
	
	private final static String TAG = SReaderApplication.LogEpub;
	
	private String author = "";
	private String bookName = "";
	private String pathName = "";
	private String metaPath = "";
	private String contentPath = "";
	private String description = "";
	private String ncxPath     = "";

	private List<String> chapterSrc  = null;
	private List<String> chapterId   = null;
	private String coverPath = "";
	private BitmapDrawable cover = null;
	
	
	private boolean epubParseMetaData(){
		ZipFile zf 		= null;
		ZipEntry ze 	= null;
		InputStream is 	= null;
		try {
			zf = new ZipFile(pathName);
			ze = zf.getEntry("META-INF/container.xml");
			is = zf.getInputStream(ze);
			
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document doc = db.parse(is);			
			metaPath = doc.getElementsByTagName("rootfile").item(0).getAttributes().getNamedItem("full-path").getNodeValue();
			
			ze = zf.getEntry(metaPath);
			is = zf.getInputStream(ze);
			
			doc = dbf.newDocumentBuilder().parse(is);
			
			author = doc.getElementsByTagName("dc:creator").item(0).getFirstChild().getNodeValue();
			bookName = doc.getElementsByTagName("dc:title").item(0).getFirstChild().getNodeValue();
			
			NodeList nl = doc.getElementsByTagName("dc:description").item(0).getChildNodes();
			for(int i = 0;i<nl.getLength();i++){
				Node n = nl.item(i);
				if(n.getNodeName().equals("p")) {
					description += n.getFirstChild().getNodeValue()+"\n";
					//Log.v("epub", n.getFirstChild().getNodeValue());
				}
			}
			
			String[] tmpStrList = metaPath.split("/");
			String sb = "";
			for(int i =0;i<tmpStrList.length-1;i++) sb += tmpStrList[i]+"/";
			contentPath = sb;
			coverPath = sb + doc.getElementById("cover-image").getAttribute("href");
			is = zf.getInputStream(zf.getEntry(coverPath));
			cover = new BitmapDrawable(is);
			if(cover == null) Log.v("epub","null");
			
			nl = doc.getElementsByTagName("manifest").item(0).getChildNodes();
			for(int i = 0; i<nl.getLength(); i++){
				Node n = nl.item(i);
				if(n.hasAttributes() && n.getNodeName().equals("item") && n.getAttributes().getNamedItem("media-type").getNodeValue().equals("application/xhtml+xml")){
					Log.v(TAG, n.getAttributes().getNamedItem("href").getNodeValue());
					this.chapterSrc.add(sb + n.getAttributes().getNamedItem("href").getNodeValue());
					this.chapterId.add(n.getAttributes().getNamedItem("id").getNodeValue());
				}
			}
			
			Node node = doc.getElementById("ncx");
			this.ncxPath = sb + node.getAttributes().getNamedItem("href").getNodeValue();
			
			chapterCount = 0;
			setContetNodeList(chapterCount);
			
		} catch (Exception e) {
			//Log.e("epub", e.getMessage());
			return false;
		}
		
		return true;
	}
	
	private boolean setContetNodeList(int i){
		try{
			String src = chapterSrc.get(i);
			ZipFile zf = new ZipFile(pathName);
			ZipEntry ze = zf.getEntry(src);
			InputStream is = zf.getInputStream(ze);
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document doc = db.parse(is);
			
			//问题？不知道这里是不是所有的epub的html都是这样子的
			NodeList nl = doc.getElementsByTagName("body").item(0).getChildNodes().item(1).getChildNodes();
			if(nl != null) {
				contentList = nl;
				listCount   = 0;
			}else {
				return false;
			}
			
		}catch(Exception e){
			Log.e(SReaderApplication.LogEpub,e.getMessage());
			return false;
		}
		return true;
	}
	
	private int listCount = 0;
	private NodeList contentList = null;
	private int chapterCount = 0;
	
	
	public Paragraph getNextParagraph(){
		Paragraph rt = new Paragraph();
		if(listCount >= contentList.getLength() /*&& setContetNodeList(++chapterCount)*/)
			return null;
		
		String tmpStr = null;
		switch(getType(contentList.item(listCount).getNodeName())){
			case p:
				if((tmpStr = contentList.item(listCount).getTextContent())!=null && !tmpStr.equals("") ){
					rt.para = contentList.item(listCount).getTextContent();
					rt.type = ParagraphType.text;
				}else{
					listCount++;
					rt = getNextParagraph();
					return rt;
				}
			//	Log.v("xxx", (String) rt.para);
				break;
			case img:
				rt.para = getImage(contentPath + contentList.item(listCount).getAttributes().getNamedItem("src").getNodeValue());
				rt.type = ParagraphType.img;
				break;
			case h1:
				rt.para = contentList.item(listCount).getTextContent();
				rt.type = ParagraphType.h1;
				break;
			case h2:
				rt.para = contentList.item(listCount).getTextContent();
				rt.type = ParagraphType.h2;
				break;
			case h3:
				rt.para = contentList.item(listCount).getTextContent();
				rt.type = ParagraphType.h3;
				break;
			case div:
				//Log.v(TAG, contentList.item(listCount).getTextContent());
				//Log.v(TAG, msg)
				NodeList nl = contentList.item(listCount).getChildNodes();
				rt.para = getImage(contentPath + nl.item(0).getAttributes().getNamedItem("src").getNodeValue());
				Log.v(TAG, nl.item(0).getAttributes().getNamedItem("src").getNodeValue());
				rt.type = ParagraphType.img;
				break;
			case unkown:
				listCount++;
				rt = getNextParagraph();
				return rt;
			default:
				listCount++;
				rt = getNextParagraph();
				return rt;
		}
		
		listCount++;
		return rt;
	}
	
	public static enum HtmlTag{
		unkown,p,img,h1,h2,h3,div;
	};
	
	private HtmlTag getType(String nodeName){
		HtmlTag tag = htmlTagMap.get(nodeName);
		if(tag!=null) return tag;
		else return HtmlTag.unkown;
	}
	
	private Bitmap getImage(String imagePath){
		BitmapDrawable bd = null;
		Bitmap bm = null;
		try{
			ZipFile zf = new ZipFile(this.pathName);
			ZipEntry ze = zf.getEntry(imagePath);
			InputStream is = zf.getInputStream(ze);
			
			BitmapFactory.Options opt = new BitmapFactory.Options();
			opt.inJustDecodeBounds = false;
			opt.inSampleSize = 2;
			bm = BitmapFactory.decodeStream(is,null,opt);
			
		}catch(Exception e){
			return null;
		}
		return bm;
	}
	
	public EpubFile(String pathname){
		author = "";
		bookName = "";
		pathName = pathname;
		//this.chapterName = new ArrayList<String>();
		this.chapterId = new ArrayList<String>();
		this.chapterSrc  = new ArrayList<String>();
	}
	
	public boolean epubFileInit(){
		if(!pathName.equals("") && !pathName.toLowerCase().endsWith(".epub")) return false;
		if(!this.epubParseMetaData()) return false;
		
		return true;
	}
	
	public String getBookAuthor(){
		return author;
	}
	
	public String getBookName(){
		return bookName;
	}
	
	public String getDescription(){
		return this.description;
	}
	
	public BitmapDrawable getCover(){
		return this.cover;
	}
	
	public List<String> getChapterSrc(){
		return this.chapterSrc;
	}
	
	private static final HashMap<String,HtmlTag> htmlTagMap = new HashMap<String,HtmlTag>();
	
	static{
		htmlTagMap.put("p", HtmlTag.p);
		htmlTagMap.put("img", HtmlTag.img);
		htmlTagMap.put("h1", HtmlTag.h1);
		htmlTagMap.put("h2", HtmlTag.h2);
		htmlTagMap.put("h3", HtmlTag.h3);
		htmlTagMap.put("div", HtmlTag.div);
	}

	public void run() {
		//TODO:i don't know whether we should use multithread?
		
	}

	public List<Paragraph> getNextChapter() {
		if(chapterCount > chapterSrc.size()) return null;
		List<Paragraph> chapters = new ArrayList<Paragraph>();
		
		setContetNodeList(chapterCount);
		chapterCount++;
		
		Paragraph para = this.getNextParagraph();
		while(para != null){
			chapters.add(para);
			para = this.getNextParagraph();
		}
		return chapters;
	}
	
	public List<Paragraph> getChapterWithNum(int num){
		if(num < 0 || num > chapterSrc.size()) return null;
		List<Paragraph> chapters = new ArrayList<Paragraph>();
		
		chapterCount = num;
		setContetNodeList(num);
		
		setContetNodeList(chapterCount);
		chapterCount++;
		
		Paragraph para = this.getNextParagraph();
		while(para != null){
			chapters.add(para);
			para = this.getNextParagraph();
		}
		return chapters;
		
	}
	
	public List<String> names = null;

	public List<String> getChapterNames(){
		if(names != null) return names;
		try{
			names = new ArrayList<String>();
			if(this.ncxPath.equals("")) return null;
			ZipFile zf = new ZipFile(pathName);
			ZipEntry ze = zf.getEntry(ncxPath);
			InputStream is = zf.getInputStream(ze);
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document doc = db.parse(is);
			for(String id:this.chapterId){
				Node n = doc.getElementById(id);
				NodeList nl = n.getChildNodes();
				//Log.v(TAG, nl.item(1).getChildNodes().item(0).getTextContent());
				names.add(nl.item(1).getChildNodes().item(0).getTextContent());
			}
		}catch(Exception e){
			
		}
		return names;
	}
}
